///*
// * Copyright © 2021 http://www.hn-szzy.com/ All rights reserved.
// */
//package com.xjh.config;
//
//import com.xjh.service.PasswordUserDetailsService;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//import org.springframework.http.HttpMethod;
//import org.springframework.security.authentication.AuthenticationManager;
//import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
//import org.springframework.security.config.annotation.web.builders.HttpSecurity;
//import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
//import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
//import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
//
///**
// * @author： 徐建华
// * @date： 2022/2/13
// * @description：
// */
////属于配置类的注解
//
//
///**
// * 继承WebSecurityConfigurerAdapter类,重写它的configure
// * <p>
// * springSecurity认证管理工作流程:::::::
// * 1.用户输入username和password
// * 2.从拦截器中获取username、password，通过UsernamePasswordAuthenticationToken构造一个未认证的Authentication对象（auth）
// * 3.通过userDetailsService获取真username/password
// * 4.过滤器将Authentication提交至认证管理器（AuthenticationManager）进行认证（具体是哪里AuthenticationProvider认证器，认证了什么）和auth.userDetailsService什么关系
// * <p>
// * 5.填充（权限信息）并存储Authentication对象
// * <p>
// * 功能概述：1.过滤请求 2.校验用户名和密码及权限
// */
//@Configuration
//@EnableWebSecurity
//public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//    //  第三种：自定义实现类就不再以上面的方式直接设置用户名和密码了，而是引入实现类,将实现类中的参数设置到其中，
//    //  设置用户名密码方式  将实现类注入到这里（根据service注解），会带回来用户名密码和权限
//    @Autowired
//    private PasswordUserDetailsService passwordUserDetailsService;
//    @Autowired
//    private PasswordAuthenticationProvider passwordAuthenticationProvider;
//
//    // 产生一个bean对象，并交给spring容器，然后上面才可以使用这个密码编码的方法
//
//    @Bean
//    public BCryptPasswordEncoder bCryptPasswordEncoder() {
//        return new BCryptPasswordEncoder();
//    }
//
//    /**
//     * 密码授权模式用到的AuthenticationManager类
//     */
//    @Override
//    @Bean
//    public AuthenticationManager authenticationManagerBean() throws Exception {
//        return super.authenticationManagerBean();
//    }
//
//
//    /**
//     * 权限认证（AuthenticationManagerBuilder auth）
//     * auth.userDetailsService:传入一个userDetailsService进行账户、密码比对
//     */
//    @Override
//    public void configure(AuthenticationManagerBuilder auth) throws Exception {
//        //  userDetailsService中一共返回三个东西，用户名、密码、权限
//        /**
//         *  passwordEncoder中包含两个方法
//         *  encode 方法用来对明文密码进行加密，返回加密之后的密文。
//         *   matches 方法是一个密码校对方法，在用户登录的时候，将用户传来的明文密码和数据库中保存的密文密码作为参数，
//         *   传入到这个方法中去，根据返回的 Boolean 值判断用户密码是否输入正确。
//         */
//        // 注入一个userDetailsService实例,这里不注释下面的就不生效了
//        // springSecurity默认认证器
//        auth.userDetailsService(passwordUserDetailsService).passwordEncoder(bCryptPasswordEncoder());
//        /**
//         * ProviderManager 是 AuthenticationManager 接口的实现类，该接口是认证相关的核心接 口，也是认证的入口。
//         * 在实际开发中，我们可能有多种不同的认证方式，例如：用户名+ 密码、邮箱+密码、手机号+验证码等，
//         * 而这些认证方式的入口始终只有一个，那就是 AuthenticationManager。
//         * 该接口的常用实现类 ProviderManager 内部会维护一个 List列表，存放多种认证方式，实际上这是委托者模式 （Delegate）的应用。
//         * 每种认证方式对应着一个 AuthenticationProvider，
//         *AuthenticationManager 根据认证方式的不同（根据传入的 Authentication 类型判断）委托 对应的 AuthenticationProvider 进行用户认证。
//         * */
//        // 这个是干啥的，回答：比如qq认证和微信认证，需要有两个userDetailsService，
//        // 上面的方式只能验证一种,不能用上面的方式，需要多个认证提供器，每个提供器都有自己的userDetailsService，负责从不同渠道得到用户名和密码，
//        // 那么是如何识别不同的提供器呢
//
////        auth.authenticationProvider(passwordAuthenticationProvider());
//
//    }
//
//    @Override
//    public void configure(HttpSecurity http) throws Exception {
//        http
//                .cors()
//                .and()
//                // 允许跨域访问
//                .csrf().disable()
//                .authorizeRequests()
//                .antMatchers("/test/**")
//                .hasAuthority("test")
//                .anyRequest().authenticated();
////                .and() //并行条件
////                .formLogin(); //可从默认的login页面登录，并且登录后跳转到配置redirect_uri
//
//    }
//
//
//    /**
//     * 请求拦截（AuthenticationManagerBuilder auth）
//     * 如果不重写这个方法，默认所有请求都需要经过认证，这个方法详细筛选了哪些请求需要经过认证
//     *
//     * 是先认证再授权，还是先授权再认证
//     */
//
////    @Override
////    public void configure(HttpSecurity http) throws Exception {
////        // 每一个方法都是一个Configurer配置器,disable()是所有配置器公用的
////        http
////                // 访问任何接口时，跳转到访问前端的login页面
////                .formLogin().loginPage("/login")
////                .and()
////                // 允许跨域访问
////                .cors()
////                // and 方法总是让我们回到 HttpSecurity，开启新一轮的 xxxConfigurer 配置。
////                .and()
////                // 关闭csrf防护，不写默认开启
////                .csrf().disable()
////                // 2.配置拦截规则（authorizeRequests（）是一个配置器，后面都是他的方法）
////                .authorizeRequests()
////
////                .antMatchers("/login", "/oauth/authorize").permitAll()
////                // 该路径请求需要该用户有xxx权限
////                .antMatchers("/test/hello").hasAuthority("xxx")
////                .antMatchers("/test/hello").hasRole("xxx")
////                // 该路径的post请求需要经过认证（这里的认证指的是什么？登录后就可以访问吗？）
////                .antMatchers(HttpMethod.POST, "/shop/order").authenticated()
////                // 对于其他的请求,都放行。（anyRequest()代表任意请求，不过优先级和先后顺序有关）
////                // anyRequest 应该放在最后，表示除了前面拦截规则之外，剩下的请求要如何处理。
////                .anyRequest().permitAll();
////    }
//
//
//    /**
//     * 密码认证
//     */
//    public PasswordAuthenticationProvider passwordAuthenticationProvider() {
//        // 设置对应的UserDetailsService
//        passwordAuthenticationProvider.setUserDetailsService(passwordUserDetailsService);
//        return passwordAuthenticationProvider;
//    }
//
//    // 第一种设置用户名密码方式：直接在代码中写死
///*
////    重写configure来设置用户名和密码
//    @Override
//    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
////        使用BCryptPasswordEncoder对象先用bean注入进来
//        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
//        String password = passwordEncoder.encode("123456");
////        通过auth.inMemoryAuthentication()设置用户名、密码、和角色
////        给密码加密后再设置密码
//        auth.inMemoryAuthentication().withUser("admin").password(password).roles("admin");
////        直接设置密码
////        auth.inMemoryAuthentication().withUser("lucy").password("123456").roles("admin");
//    }
//
//*/
//    // 第二种：将用户名密码写到配置文件中写死，该文件添加@EnableWebSecurity注解
//    /*spring:
//  security:
//    user:
//      name: zhangsan
//      password: 123456*/
//
//
//    /**
//     * 除了authenticated()方法和permitAll()方法外,还有一些其他方法用来定义该如何保护请求.
//     * access(String) 如果给定的SpEL表达式计算结果为true，就允许访问
//     * anonymous() 允许匿名用户访问
//     * authenticated() 允许认证的用户进行访问
//     * denyAll() 无条件拒绝所有访问
//     * fullyAuthenticated() 如果用户是完整认证的话（不是通过Remember-me功能认证的），就允许访问
//     * hasAuthority(String) 如果用户具备给定权限的话就允许访问
//     * hasAnyAuthority(String…)如果用户具备给定权限中的某一个的话，就允许访问
//     * hasRole(String) 如果用户具备给定角色(用户组)的话,就允许访问/
//     * hasAnyRole(String…) 如果用户具有给定角色(用户组)中的一个的话,允许访问.
//     * hasIpAddress(String 如果请求来自给定ip地址的话,就允许访问.
//     * not() 对其他访问结果求反.
//     * permitAll() 无条件允许访问
//     * rememberMe() 如果用户是通过Remember-me功能认证的，就允许访问
//     *
//     * */
//}
